import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;


/**
 * The distance matrix represents a distance CSV-file for a specific age in an NxN matrix. From this class,
 * you can access the distance of certain elements in the matrix and determine, whether this cell conforms to 
 * a match or a mismatch via isMatchAt()-method
 * @author tbergmueller
 *
 */
public class DistanceMatrix 
{
	private double[][] _dist;
	private int[] _classes;
	
	private int _nrOfColumnsAndRows;
	
	
	
	/**
	 * Converts a String (filename) to the class number
	 * @param name		
	 * @param filename
	 * @return
	 */
	private static int strToClass(String name, String filename)
	{
		if (name == null || name.length() < 6)
		{
			return 0;
		}

		String strNr = "0";

		try
		{
			strNr = name.substring(2, 5);
		}
		catch (Exception e)
		{
			e.printStackTrace();
			System.out.println(name);
			System.out.println(filename);
		}

		int nr = Integer.parseInt(strNr);

		int c = 2 * nr;
		if (name.substring(5, 6).equals("R"))
		{
			c++;
		}

		return c;
	}
	
	/**
	 * Returns the Width of the Matrix (number of horizontal elements)
	 * @return
	 */
	public int getWidth()
	{
		return _nrOfColumnsAndRows;
	}
	
	/**
	 * Returns the height of the matrix (number of vertical elements)
	 * @return
	 */
	public int getHeight()
	{
		return _nrOfColumnsAndRows;
	}
	
	/**
	 * Returns the content of a distance cell at certain coordinates
	 * @param x horizontal
	 * @param y vertical
	 * @return
	 */
	public double distAt(int x, int y)
	{
		return _dist[x][y];
	}
	
	/**
	 * Returns whether this cell corresponds to a match (true) or a mismatch (false). A match is, when the class of the column corresponds with the class of the row.
	 * @param x horizontal coord
	 * @param y vertical coord
	 * @return true if representing a match, false otherwise
	 */
	public boolean isMatchAt(int x, int y)
	{
		return _classes[x] == _classes[y];
	}
	
	
	private DistanceMatrix(double[][] distances, int[] classes)
	{
		_dist = distances;
		_classes = classes;
		
	}
	
	/**
	 * Builds a DistanceMatrix-Representation of a distance-CSV-file. you have to specify the number of images
	 * because this was a faster implementation
	 * @param file	The distance-matrix file
	 * @param nrOfImages the number of images whose distance is encoded in the CSV
	 * @return
	 * @throws IOException In case something goes wrong with file processing
	 */
	public static DistanceMatrix fromFile(File file, int nrOfImages) throws IOException
	{
		BufferedReader br;
		
		
		double[][] oDistances = new double[nrOfImages][nrOfImages];
		int[] oClasses = new int[nrOfImages];
				
		br = new BufferedReader(new FileReader(file.getAbsoluteFile()));

			
		// read first line
		String line = br.readLine();
		
		// read filenames
		String[] parts = line.split(",");

		// First line contains the filenames - from these the class (PersonID) of the file can be obtained
		for (int i = 2; i < parts.length; i++)
		{
			oClasses[i - 2] = strToClass(parts[i], file.getName());
			//System.out.println(parts[i] + " ... " + oClasses[i - 2]);
		}

		// Skip the "classes" line in the file, since we already obtained personIDs from the filename in the first row
		line = br.readLine();
				
		// read actual first dataline
		line = br.readLine();

		
		int lineCnt = 0;

		while (line != null)
		{
			// System.out.println(line);

			parts = line.split(",");

			for (int i = 0; i < parts.length - 2; i++)
			{
				oDistances[lineCnt][i] = Double.parseDouble(parts[i + 2]);				
			}

			lineCnt++;
			line = br.readLine();
		}
		
		br.close();
		DistanceMatrix d = new DistanceMatrix(oDistances,oClasses);
		d._nrOfColumnsAndRows = nrOfImages;
		
		return d;
	}

}
